package com.rm.zeyou.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rm.zeyou.constant.CommonConstants;
import com.rm.zeyou.constant.NumberConstants;
import com.rm.zeyou.entity.*;
import com.rm.zeyou.exception.ErrorCodeException;
import com.rm.zeyou.exception.ErrorCodeExceptionEnum;
import com.rm.zeyou.mapper.*;
import com.rm.zeyou.pay.wxpay.constants.WechatPayOutConstants;
import com.rm.zeyou.pay.wxpay.transfer.service.TransferNewService;
import com.rm.zeyou.pay.wxpay.transfer.vo.TransferQueryResponse;
import com.rm.zeyou.response.ApiRestResponse;
import com.rm.zeyou.service.UserPayoutDetailService;
import com.rm.zeyou.util.check.CheckEmptyUtil;
import com.rm.zeyou.vo.request.SelectUserPayoutIndexVo;
import com.rm.zeyou.vo.response.ConfirmPayoutResponseVo;
import com.rm.zeyou.vo.response.SelectUserPayoutIndexResponseVo;
import com.rm.zeyou.vo.response.UserPayoutVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 用户提现记录表 服务实现类
 * </p>
 *
 * @author YanYang
 * @since 2025-03-12 15:55:09
 */
@Service
public class UserPayoutDetailServiceImpl extends ServiceImpl<UserPayoutDetailMapper, UserPayoutDetail> implements UserPayoutDetailService {
    @Resource
    private UserPayoutDetailMapper userPayoutDetailMapper;
    @Resource
    private UserBackMapper userBackMapper;
    @Resource
    private PayoutConfigMapper payoutConfigMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserConsumeDetailMapper userConsumeDetailMapper;
    @Resource
    private UserZfbCountMapper userZfbCountMapper;
    @Resource
    private PayoutDictConfigMapper payoutDictConfigMapper;
    @Resource
    private AgreementConfigMapper agreementConfigMapper;
    @Resource
    private TransferNewService transferNewService;
    @Resource
    private WxpayConfigMapper wxpayConfigMapper;
    @Resource
    private ApplicationConfigMapper applicationConfigMapper;

    @Override
    public ApiRestResponse<SelectUserPayoutIndexResponseVo> selectUserPayoutIndex(User user, SelectUserPayoutIndexVo requestVo) {
        SelectUserPayoutIndexResponseVo responseVo = new SelectUserPayoutIndexResponseVo();
        BigDecimal payoutFee = new BigDecimal(payoutDictConfigMapper.selectValue("payout_fee")).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        BigDecimal payoutTax = new BigDecimal(payoutDictConfigMapper.selectValue("payout_tax")).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        BigDecimal minPayoutPrice = new BigDecimal(payoutDictConfigMapper.selectValue("min_payout_price"));
        BigDecimal maxPayoutPrice = new BigDecimal(payoutDictConfigMapper.selectValue("max_payout_price"));

        responseVo.setMinPayoutPrice(minPayoutPrice);
        responseVo.setMaxPayoutPrice(maxPayoutPrice);
        responseVo.setUserBalance(user.getUserBalance());
        responseVo.setTaxPrice(requestVo.getPayoutPrice().multiply(payoutTax).setScale(2,RoundingMode.HALF_UP));
        responseVo.setFeePrice(requestVo.getPayoutPrice().multiply(payoutFee).setScale(2,RoundingMode.HALF_UP));

        int userBackCount = userBackMapper.selectCount(new LambdaQueryWrapper<UserBack>()
                .eq(UserBack::getUserId, user.getId())).intValue();
        if (userBackCount > 0) {
            responseVo.setIsBindBack(NumberConstants.ONE_CONSTANTS);
        } else {
            responseVo.setIsBindBack(NumberConstants.ZERO_CONSTANTS);
        }

        if (CheckEmptyUtil.isEmpty(user.getOpenId())) {
            responseVo.setIsBindWx(NumberConstants.ZERO_CONSTANTS);
        } else {
            responseVo.setIsBindWx(NumberConstants.ONE_CONSTANTS);
        }

        UserZfbCount userZfbCount = userZfbCountMapper.selectOne(new LambdaQueryWrapper<UserZfbCount>().eq(UserZfbCount::getUserId, user.getId()));
        if (CheckEmptyUtil.isEmpty(userZfbCount)) {
            responseVo.setIsBindZfb(NumberConstants.ZERO_CONSTANTS);
        } else {
            responseVo.setIsBindZfb(NumberConstants.ONE_CONSTANTS);
        }
        String payoutIllustrate = agreementConfigMapper.selectValue("payout_illustrate");
        responseVo.setPayoutIllustrate(payoutIllustrate);

        return ApiRestResponse.success(responseVo);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse<Integer> userPayout(User user, UserPayoutVo requestVo) {
        PayoutConfig payoutConfig = payoutConfigMapper.selectById(requestVo.getPayoutWayId());
        if (CheckEmptyUtil.isEmpty(payoutConfig) && requestVo.getPayoutWayId() !=4 ) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAYOUT_WAY_EMPTY);
        }
        if (requestVo.getPayoutWayId() == 4) {
            UserBack userBack = userBackMapper.selectById(requestVo.getUserBackId());
            if (CheckEmptyUtil.isEmpty(userBack)) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.USER_BACK_EMPTY);
            }
        }
        if (requestVo.getPayoutWayId() == 3) {
            UserZfbCount userZfbCount = userZfbCountMapper.selectOne(new LambdaQueryWrapper<UserZfbCount>().eq(UserZfbCount::getUserId, user.getId()));
            if (CheckEmptyUtil.isEmpty(userZfbCount)) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.ZFB_COUNT_EMPTY);
            }
        }
        if (requestVo.getPayoutWayId() == 2) {
            String openId;
            if (requestVo.getWithdrawalsEnvironment().equals("H5")) {
                openId = user.getOpenId();
            } else {
                openId = user.getAppOpenId();
            }
            if (CheckEmptyUtil.isEmpty(openId)) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.NOT_BIND_WX);
            }
        }

        BigDecimal payoutFee = new BigDecimal(payoutDictConfigMapper.selectValue("payout_fee")).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        BigDecimal payoutTax = new BigDecimal(payoutDictConfigMapper.selectValue("payout_tax")).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        BigDecimal minPayoutPrice = new BigDecimal(payoutDictConfigMapper.selectValue("min_payout_price"));
        BigDecimal maxPayoutPrice = new BigDecimal(payoutDictConfigMapper.selectValue("max_payout_price"));
        if (requestVo.getPayoutPrice().compareTo(minPayoutPrice) < 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAYOUT_MIN_PRICE.getCode(), String.format(ErrorCodeExceptionEnum.PAYOUT_MIN_PRICE.getMsg(), minPayoutPrice.toPlainString()));
        }

        if (requestVo.getPayoutPrice().compareTo(maxPayoutPrice) > 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAYOUT_MAX_PRICE.getCode(), String.format(ErrorCodeExceptionEnum.PAYOUT_MAX_PRICE.getMsg(), minPayoutPrice.toPlainString()));
        }
        if (requestVo.getPayoutPrice().compareTo(user.getUserBalance()) > 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAYOUT_PRICE_ENOUGH);
        }

        Integer subBalance = userMapper.subBalance(user.getId(), requestVo.getPayoutPrice());

        if (subBalance == 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.PAYOUT_ERROR);
        }

        UserPayoutDetail userPayoutDetail = new UserPayoutDetail();
        userPayoutDetail.setUserId(user.getId());
        userPayoutDetail.setPayoutType(Math.toIntExact(requestVo.getPayoutWayId()));
        userPayoutDetail.setPayoutPrice(requestVo.getPayoutPrice());
        BigDecimal fee = requestVo.getPayoutPrice().multiply(payoutFee);
        userPayoutDetail.setPayoutFee(fee);
        BigDecimal tax = requestVo.getPayoutPrice().multiply(payoutTax);
        userPayoutDetail.setPayoutTax(tax);
        userPayoutDetail.setRealPrice(requestVo.getPayoutPrice().subtract(fee).subtract(tax));
        if (requestVo.getPayoutWayId() == 4) {
            UserBack userBack = userBackMapper.selectById(requestVo.getUserBackId());
            userPayoutDetail.setBackName(userBack.getBackName());
            userPayoutDetail.setBackUserName(userBack.getBackUserName());
            userPayoutDetail.setBackIdcard(userBack.getBackIdcard());
            userPayoutDetail.setBackBranch(userBack.getBackBranch());
        }
        userPayoutDetail.setWithdrawalsEnvironment(requestVo.getWithdrawalsEnvironment());
        userPayoutDetailMapper.insert(userPayoutDetail);


        UserConsumeDetail userConsumeDetail = new UserConsumeDetail();
        userConsumeDetail.setUserId(user.getId());
        userConsumeDetail.setUserPayoutId(userPayoutDetail.getId());
        userConsumeDetail.setConsumptionPrice(requestVo.getPayoutPrice());
        userConsumeDetail.setConsumptionType(CommonConstants.CONSUMPTION_PAYOUT);
        userConsumeDetail.setConsumptionDescribe("提现审核中");
        int insert = userConsumeDetailMapper.insert(userConsumeDetail);


        return ApiRestResponse.success(insert);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void updateUserWithdrawals() {
        List<UserPayoutDetail> userPayoutDetails = userPayoutDetailMapper.selectNotSuccessOrFailList();
        if (!CheckEmptyUtil.isEmpty(userPayoutDetails)) {
            for (UserPayoutDetail userPayoutDetail : userPayoutDetails) {
                TransferQueryResponse transferQueryResponse = transferNewService.queryTransferByOutBillNo(userPayoutDetail.getWxWithdrawalsNo());
                if (!CheckEmptyUtil.isEmpty(transferQueryResponse)) {
                    userPayoutDetail.setWxWithdrawalsStatus(transferQueryResponse.getState());
                    UserConsumeDetail userConsumeDetail = userConsumeDetailMapper.selectOne(new LambdaQueryWrapper<UserConsumeDetail>()
                            .eq(UserConsumeDetail::getUserPayoutId, userPayoutDetail.getId()));
                    if (transferQueryResponse.getState().equals(WechatPayOutConstants.SUCCESS)) {
                        userPayoutDetail.setPayoutStatus(NumberConstants.ONE_CONSTANTS);
                        userConsumeDetail.setConsumptionDescribe("提现成功");
                    }

                    if (transferQueryResponse.getState().equals(WechatPayOutConstants.FAIL)) {
                        userPayoutDetail.setPayoutStatus(NumberConstants.TWO_CONSTANTS);
                        userConsumeDetail.setConsumptionDescribe("提现失败");
                        userMapper.addBalance(userPayoutDetail.getUserId(), userPayoutDetail.getPayoutPrice());
                    }
                    userPayoutDetailMapper.updateById(userPayoutDetail);
                    userConsumeDetailMapper.updateById(userConsumeDetail);
                }
            }
        }
    }

    @Override
    public ApiRestResponse<List<ConfirmPayoutResponseVo>> userConfirmPayout(User user) {
        List<UserPayoutDetail> userPayoutDetails = userPayoutDetailMapper.selectList(new LambdaQueryWrapper<UserPayoutDetail>()
                .eq(UserPayoutDetail::getWxWithdrawalsStatus, "WAIT_USER_CONFIRM")
                .eq(UserPayoutDetail::getUserId,user.getId()));
        List<ConfirmPayoutResponseVo> responseVoList = new ArrayList<>(userPayoutDetails.size());
        if (!CheckEmptyUtil.isEmpty(userPayoutDetails)) {
            for (UserPayoutDetail userPayoutDetail : userPayoutDetails) {
                ConfirmPayoutResponseVo responseVo = new ConfirmPayoutResponseVo();
                responseVo.setId(userPayoutDetail.getId());
                responseVo.setPackageInfo(userPayoutDetail.getPackageInfo());
                String mchId = wxpayConfigMapper.selectOneData("mchId");
                responseVo.setMuchId(mchId);
                String accountAppid = applicationConfigMapper.selectOneData("account_appid");
                responseVo.setH5Appid(accountAppid);
                String appAppid = applicationConfigMapper.selectOneData("app_appid");
                responseVo.setAppAppid(appAppid);
                responseVoList.add(responseVo);
            }
        }
        return ApiRestResponse.success(responseVoList);
    }
}
